package nature.nano.util.accepter.schema;

import java.util.HashMap;
import java.util.Map;

import nature.nano.component.EmptyProps;
import nature.nano.component.SimpleProps;
import nature.nano.component.Strings;
import nature.nano.iface.Accepter;

class SchemaDetectorHelper {
	
	private SchemaDetectorHelper parent;
	private String type;
	private long appearCount = 0;
	private long contentAllSize = 0;
	private long contentMaxSize = 0;
	private long contentAppearCount = 0;
	private Map<String, SchemaDetectorHelper> children = new HashMap<String, SchemaDetectorHelper>();
	
	private class PropInfo {
		private long appearCount = 0;
		private long keyMaxSize = 0;
		private long keyAllSize = 0;
		private long valueMaxSize = 0;
		private long valueAllSize = 0;
		
		public void onProp(String key, String value) {
			appearCount += 1;
			keyMaxSize = (keyMaxSize < key.length()) ? key.length() : keyMaxSize;
			keyAllSize += key.length();
			valueMaxSize = (valueMaxSize < value.length()) ? value.length() : valueMaxSize;
			valueAllSize += value.length();							
		}
	}
	
	private Map<String, PropInfo> propInfos = new HashMap<String, PropInfo>();
	
	public SchemaDetectorHelper addChild(String type) {
		if (!children.containsKey(type)) {
			SchemaDetectorHelper child = new SchemaDetectorHelper();
			child.parent = this;
			child.type = type;
			children.put(type, child);
		}
		SchemaDetectorHelper child = children.get(type);
		child.appearCount += 1;
		return child;
	}
	
	public SchemaDetectorHelper getParent() {
		return parent;
	}
	
	public void onContent(long size) {
		contentAppearCount += 1;
		contentAllSize += size;
		contentMaxSize = (contentMaxSize < size) ? size : contentMaxSize; 
	}
	
	public void onProp(String key, String value) {
		if (!propInfos.containsKey(key)) {
			PropInfo info = new PropInfo();
			propInfos.put(key, info);
		}
		propInfos.get(key).onProp(key, value);
	}
	
	public void flush(Accepter accepter) {
		flush(this, accepter);
	}
	
	private static void flush(SchemaDetectorHelper node, Accepter accepter) {
		for (String key : node.children.keySet()) {
			SchemaDetectorHelper child = node.children.get(key);
			
			SimpleProps props = new SimpleProps(Strings.appearCount, Long.toString(child.appearCount));
			if (child.contentAppearCount > 0) {
				props.add(Strings.contentMaxSize, Long.toString(child.contentMaxSize));
				props.add(Strings.contentAllSize, Long.toString(child.contentAllSize));
				props.add(Strings.contentAppearCount, Long.toString(child.contentAppearCount));			
			}
			accepter.onBegin("tag:" + child.type, props);			
						
			if (child.propInfos.size() > 0) {
				accepter.onBegin(Strings.propsInfo, EmptyProps.instance);			
				for (String propName : child.propInfos.keySet()) {
					SchemaDetectorHelper.PropInfo info = child.propInfos.get(propName);
					SimpleProps propProps = new SimpleProps(
						Strings.appearCount, Long.toString(info.appearCount),
						Strings.valueMaxSize, Long.toString(info.valueMaxSize),
						Strings.valueAllSize, Long.toString(info.valueAllSize));
					accepter.onBegin(propName, propProps);			
					accepter.onEnd(propName);				
				}
				accepter.onEnd(Strings.propsInfo);
			}
			
			
			flush(child, accepter);
			accepter.onEnd("tag:" + child.type);
		}
	}
	
}
